package com.wande.dataplatform.filecollection.common.utils;

import cn.hutool.core.util.StrUtil;
import com.wande.dataplatform.filecollection.common.enums.FileCollectionErrorCode;
import com.wande.dataplatform.filecollection.common.exception.FileCollectionException;
import com.wande.dataplatform.filecollection.config.MinioProperties;
import io.minio.*;
import io.minio.errors.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * MinIO工具类
 *
 * @author wande
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtils {

    private final MinioClient minioClient;
    private final MinioProperties minioProperties;

    /**
     * 获取MinioClient实例
     */
    public MinioClient getMinioClient() {
        return minioClient;
    }

    /**
     * 确保存储桶存在
     */
    public void ensureBucketExists() {
        try {
            String bucketName = minioProperties.getBucketName();
            boolean exists = minioClient.bucketExists(
                BucketExistsArgs.builder().bucket(bucketName).build()
            );

            if (!exists) {
                minioClient.makeBucket(
                    MakeBucketArgs.builder().bucket(bucketName).build()
                );
                log.info("创建MinIO存储桶: {}", bucketName);
            }
        } catch (Exception e) {
            log.error("检查或创建MinIO存储桶失败", e);
            throw new FileCollectionException(FileCollectionErrorCode.MINIO_CONNECTION_FAILED, e);
        }
    }

    /**
     * 上传文件
     *
     * @param inputStream 文件输入流
     * @param fileName    文件名
     * @param contentType 内容类型
     * @param isStructured 是否为结构化文件
     * @return 文件存储路径
     */
    public String uploadFile(InputStream inputStream, String fileName, String contentType, boolean isStructured) {
        try {
            ensureBucketExists();

            // 生成存储路径
            String objectName = generateObjectName(fileName, isStructured);

            // 上传文件
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .stream(inputStream, -1, 10485760) // 10MB part size
                    .contentType(contentType)
                    .build()
            );

            log.info("文件上传成功: {}", objectName);
            return objectName;

        } catch (Exception e) {
            log.error("文件上传失败: {}", fileName, e);
            throw new FileCollectionException(FileCollectionErrorCode.MINIO_UPLOAD_FAILED, e);
        }
    }

    /**
     * 下载文件
     *
     * @param objectName 对象名称
     * @return 文件输入流
     */
    public InputStream downloadFile(String objectName) {
        try {
            return minioClient.getObject(
                GetObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
        } catch (Exception e) {
            log.error("文件下载失败: {}", objectName, e);
            throw new FileCollectionException(FileCollectionErrorCode.MINIO_DOWNLOAD_FAILED, e);
        }
    }

    /**
     * 删除文件
     *
     * @param objectName 对象名称
     */
    public void deleteFile(String objectName) {
        try {
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
            log.info("文件删除成功: {}", objectName);
        } catch (Exception e) {
            log.error("文件删除失败: {}", objectName, e);
            throw new FileCollectionException(FileCollectionErrorCode.MINIO_DELETE_FAILED, e);
        }
    }

    /**
     * 检查文件是否存在
     *
     * @param objectName 对象名称
     * @return true-存在，false-不存在
     */
    public boolean fileExists(String objectName) {
        try {
            minioClient.statObject(
                StatObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .build()
            );
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取文件访问URL
     *
     * @param objectName 对象名称
     * @param expiry     过期时间（秒）
     * @return 访问URL
     */
    public String getFileUrl(String objectName, int expiry) {
        try {
            return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(objectName)
                    .expiry(expiry)
                    .build()
            );
        } catch (Exception e) {
            log.error("获取文件URL失败: {}", objectName, e);
            throw new FileCollectionException(FileCollectionErrorCode.MINIO_CONNECTION_FAILED, e);
        }
    }

    /**
     * 生成对象名称（存储路径）
     *
     * @param fileName     文件名
     * @param isStructured 是否为结构化文件
     * @return 对象名称
     */
    private String generateObjectName(String fileName, boolean isStructured) {
        String prefix = isStructured 
            ? minioProperties.getStructuredPrefix() 
            : minioProperties.getUnstructuredPrefix();

        // 按日期分目录存储
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

        // 生成唯一文件名（时间戳 + 原文件名）
        String timestamp = String.valueOf(System.currentTimeMillis());
        String uniqueFileName = timestamp + "_" + fileName;

        return prefix + datePath + "/" + uniqueFileName;
    }
}
